Skip to content

Fix path traversal in profile operations#55

Open
AAtomical wants to merge 3 commits into
Microck:masterfrom
AAtomical:fix/profile-path-traversal
Open

Fix path traversal in profile operations#55
AAtomical wants to merge 3 commits into
Microck:masterfrom
AAtomical:fix/profile-path-traversal

Conversation

@AAtomical

@AAtomical AAtomical commented Jul 19, 2026

Copy link
Copy Markdown

Reject profile names containing path separators or traversal sequences to prevent arbitrary filesystem delete/create/symlink.

Fixes #54

Greptile Summary

This PR hardens profile filesystem operations against unsafe profile names. The main changes are:

  • Adds safeName validation before profile create, delete, and activate operations.
  • Rejects empty names, non-string names, path separators, traversal names, and dot-only names.
  • Adds tests for rejected traversal inputs and accepted direct-child profile names.
  • Binds the server listener explicitly to 127.0.0.1.

Confidence Score: 5/5

Safe to merge with low risk.

Profile operations now validate names before path construction, and the previously reported dot-name case is covered by validation and tests.

No files require special attention.

T-Rex T-Rex Logs

What T-Rex did

  • Unit tests were run and all tests passed (2/2) in the T-Rex suite.
  • The manager harness was executed to validate profile name handling and safe profile operations, confirming that invalid names throw an error and that create/activate and delete behaviors succeed.
  • The API harness was executed to verify API responses for invalid and valid profile names, confirming 400 for invalid requests and 200 for safe operations.
  • A parent-revision comparison artifact was captured to verify that the baseline HEAD^ contained the same validation behavior as the current change.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
server/profile-manager.js Adds safeName validation before profile create/delete/activate operations to reject traversal, separators, empty values, and non-direct child paths.
server/profile-manager.test.js Adds focused tests covering rejected traversal/dot profile names and accepted direct-child profile names.
server/index.js Binds the local server listener explicitly to 127.0.0.1 and updates the startup URL accordingly.

Sequence Diagram

sequenceDiagram
participant Client
participant API as Profile API
participant PM as profile-manager
participant FS as Filesystem

Client->>API: create/delete/activate profile(name)
API->>PM: profile operation(name)
PM->>PM: safeName(name)
alt invalid name
    PM-->>API: throw Invalid profile name
    API-->>Client: 400 error
else valid direct-child name
    PM->>FS: create/remove/symlink under PROFILES_DIR
    FS-->>PM: success
    PM-->>API: "{ success: true }"
    API-->>Client: success response
end
Loading

Reviews (2): Last reviewed commit: "Add regression test for safeName path co..." | Re-trigger Greptile

Reject profile names containing path separators or traversal
sequences to prevent arbitrary filesystem delete/create/symlink.

Fixes Microck#54
@vercel

vercel Bot commented Jul 19, 2026

Copy link
Copy Markdown

@AAtomical is attempting to deploy a commit to the Projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

This PR prevents profile operations from acting on path-traversal names by rejecting separators and .. sequences.

  • createProfile, deleteProfile, and activateProfile now fail with Invalid profile name for unsafe names.
  • Existing callers using nested or otherwise invalid profile names may be incompatible.
  • Add tests covering valid names, rejected traversal inputs, and protection against arbitrary filesystem operations; verify the unauthenticated /api/tmp, /api/music, and video deletion concerns separately.

Walkthrough

Added safeName(name) validation in server/profile-manager.js. Profile creation, deletion, and activation now reject empty names and names containing /, \, or .. with Error('Invalid profile name') before performing filesystem operations. Existing directory and activation behavior remains unchanged for valid names.


Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/profile-manager.js`:
- Around line 9-14: Update safeName to reject "." and enforce that the resolved
profile path is a direct child of PROFILES_DIR before deleteProfile or
activateProfile performs filesystem operations; add a regression test covering
"." and path containment.
- Around line 68-69: Require authentication and authorization for profile
mutations before invoking deleteProfile or the activation operation. Update the
DELETE /api/profiles/:name and POST /api/profiles/:name/activate handlers to
validate the requester’s permission to manage the supplied profile, while
preserving safeName validation and rejecting unauthorized requests before any
deletion or OPENCODE_DIR change occurs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: cfeb784a-0b64-41d0-b275-fa194984f601

📥 Commits

Reviewing files that changed from the base of the PR and between 2dac95d and 8dcf042.

📒 Files selected for processing (1)
  • server/profile-manager.js

Comment thread server/profile-manager.js
Comment on lines +9 to +14
function safeName(name) {
if (!name || name.includes('/') || name.includes('\\') || name.includes('..')) {
throw new Error('Invalid profile name');
}
return name;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Path Traversal (CWE-22): Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

Reachability: External

Reject . and enforce path containment.

safeName('.') passes validation, but path.join(PROFILES_DIR, '.') resolves to PROFILES_DIR. Consequently, deleteProfile('.') recursively deletes the entire profiles directory, and activateProfile('.') can point OPENCODE_DIR at the profiles root. Reject . and verify the resolved target is a direct child before filesystem operations; add a regression test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/profile-manager.js` around lines 9 - 14, Update safeName to reject "."
and enforce that the resolved profile path is a direct child of PROFILES_DIR
before deleteProfile or activateProfile performs filesystem operations; add a
regression test covering "." and path containment.

Comment thread server/profile-manager.js
Comment on lines 68 to +69
function deleteProfile(name) {
safeName(name);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Authorization Bypass (CWE-862): Missing Authorization

Reachability: External

Require authorization before profile deletion and activation.

The supplied DELETE /api/profiles/:name and POST /api/profiles/:name/activate handlers pass request-controlled names directly to these methods without an ownership or permission check. safeName prevents traversal but still lets any unauthenticated caller delete another non-active profile or switch the global OPENCODE_DIR. Enforce authentication and authorization before invoking these operations.

Also applies to: 81-82

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/profile-manager.js` around lines 68 - 69, Require authentication and
authorization for profile mutations before invoking deleteProfile or the
activation operation. Update the DELETE /api/profiles/:name and POST
/api/profiles/:name/activate handlers to validate the requester’s permission to
manage the supplied profile, while preserving safeName validation and rejecting
unauthorized requests before any deletion or OPENCODE_DIR change occurs.

Comment thread server/profile-manager.js
@Microck

Microck commented Jul 19, 2026

Copy link
Copy Markdown
Owner

@AAtomical Thanks for the PR! Feel free to fix the issues notified by Greptile and CodeRabbit, afterwards I will merge to main.

AAtomical added a commit to AAtomical/opencode-studio that referenced this pull request Jul 22, 2026
…to localhost

Addresses CodeRabbit/Greptile review on Microck#55:
- safeName now requires the name to resolve to a DIRECT child of PROFILES_DIR,
  rejecting '.', '..', path separators, absolute and empty names. Previously
  safeName('.') passed and deleteProfile('.') wiped the entire profiles dir.
- Bind the server to 127.0.0.1 so the unauthenticated profile/auth endpoints are
  not reachable from the network (CWE-862 external reachability).
…to localhost

Addresses CodeRabbit/Greptile review on Microck#55:
- safeName now requires the name to resolve to a DIRECT child of PROFILES_DIR,
  rejecting '.', '..', path separators, absolute and empty names. Previously
  safeName('.') passed and deleteProfile('.') wiped the entire profiles dir.
- Bind the server to 127.0.0.1 so the unauthenticated profile/auth endpoints are
  not reachable from the network (CWE-862 external reachability).
@AAtomical
AAtomical force-pushed the fix/profile-path-traversal branch from e1f7c6f to c3e17fe Compare July 22, 2026 20:12
AAtomical added a commit to AAtomical/opencode-studio that referenced this pull request Jul 22, 2026
Covers '.' and traversal names rejected, direct-child names accepted
(CodeRabbit/Greptile follow-up on Microck#55). Exports safeName for the test.
AAtomical added a commit to AAtomical/opencode-studio that referenced this pull request Jul 22, 2026
Covers '.' and traversal names rejected, direct-child names accepted
(CodeRabbit/Greptile follow-up on Microck#55). Exports safeName for the test.
@AAtomical
AAtomical force-pushed the fix/profile-path-traversal branch from d63ca39 to 3212daf Compare July 22, 2026 20:16
Covers '.' and traversal names rejected, direct-child names accepted
(CodeRabbit/Greptile follow-up on Microck#55). Exports safeName for the test.
@AAtomical
AAtomical force-pushed the fix/profile-path-traversal branch from 3212daf to 9ae0139 Compare July 22, 2026 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unauthenticated File Read via /api/tmp and /api/music

2 participants